package com.znf.biz.system.service.impl;

import cn.hutool.core.codec.Base58;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import com.google.code.kaptcha.Producer;
import com.znf.base.exception.BizException;
import com.znf.biz.system.service.IAuthService;
import com.znf.biz.system.service.ISysUserService;
import com.znf.config.CustomUserDetails;
import com.znf.biz.system.constant.RedisKeyConstant;
import com.znf.biz.system.dto.req.LoginReqDto;
import com.znf.biz.system.dto.resp.CaptchaRespDto;
import com.znf.biz.system.dto.resp.LoginRespDto;
import com.znf.biz.system.dto.resp.PubKeyRespDto;
import com.znf.util.JwtUtils;
import com.znf.common.util.RedisUtils;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.security.KeyPair;

@Data
@Slf4j
@Service
public class AuthServiceImpl implements IAuthService {

    private final Producer producer;

    private final RedisTemplate<String, Object> redisTemplate;

    private final ISysUserService sysUserService;

    private final AuthenticationManager authenticationManager;

    private final JwtUtils jwtUtil;

    private final RedisUtils redisUtils;

    @Override
    public CaptchaRespDto getCaptcha() throws IOException {
        String captchaId = UUID.fastUUID().toString(true);
        String text = producer.createText();
        BufferedImage image = producer.createImage(text);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();

        ImageIO.write(image, "png", baos);
        byte[] byteArray = baos.toByteArray();
        String captchaImage = Base64.encode(byteArray);
        CaptchaRespDto data = new CaptchaRespDto();
        data.setCaptchaId(captchaId);
        data.setData(captchaImage);
        String key = RedisKeyConstant.getKey(RedisKeyConstant.AUTH_CAPTCHA, captchaId);
        redisUtils.set(key, text, 300);
        return data;
    }

    @Override
    public PubKeyRespDto getPubKey() {
        String keyId = UUID.fastUUID().toString(true);
        KeyPair keyPair = SecureUtil.generateKeyPair("EC");
        String base58PubKey = Base58.encode(keyPair.getPublic().getEncoded());
        String base58PrivateKey = Base58.encode(keyPair.getPrivate().getEncoded());
        PubKeyRespDto data = new PubKeyRespDto();
        data.setKeyId(keyId);
        data.setPubKey(base58PubKey);
        String key = RedisKeyConstant.getKey(RedisKeyConstant.AUTH_PRIVATE_KEY, keyId);
        redisUtils.set(key, base58PrivateKey, 300);
        return data;
    }

    @Override
    public LoginRespDto login(LoginReqDto param) {
        // 验证图形验证码
        String captchaId = param.getCaptchaId();
        String key = RedisKeyConstant.getKey(RedisKeyConstant.AUTH_CAPTCHA, captchaId);
        String captcha = redisUtils.getStr(key);
        if (StrUtil.isNotBlank(captcha)) {
            redisUtils.del(key);
        }
        if (!param.getCaptcha().equalsIgnoreCase(captcha)) {
            throw new BizException("验证码错误");
        }
        Authentication authenticate = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(param.getUsername(), param.getPassword()));
        CustomUserDetails customUserDetails = (CustomUserDetails) authenticate.getPrincipal();
        String userRedisKey = RedisKeyConstant.getKey(RedisKeyConstant.AUTH_USER, param.getUsername());
        redisUtils.set(userRedisKey, customUserDetails, 7 * 24 * 3600);
        String token = jwtUtil.generatorToken(customUserDetails);
        LoginRespDto data = new LoginRespDto();
        data.setToken(token);
        return data;
    }

}
